/**
 * Copyright (c) 2018, Alex. All rights reserved.
 */
package com.oschina.bottle.poi.imp;

import com.oschina.bottle.poi.FileInfo;
import com.oschina.bottle.poi.Head;
import com.oschina.bottle.poi.Importer;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;

/**
 * Excel文件导入
 *
 * @author <a href="mailto:zhongchao@gegejia.com">zhong</a>
 * @version 1.0 2018/1/22
 * @since 1.0
 */
public class ExcelImporter implements Importer {

    @Override
    public void resolve(FileInfo fileInfo) throws IOException {
        ExcelHandler handler = new ExcelHandler();
        handler.init(fileInfo);
        handler.resolveData(fileInfo);
    }

    class ExcelHandler {

        /**
         * 表头所在的行
         */
        private int headerIndex;

        /**
         * 表单编号
         */
        private int sheetIndex = 1;

        /**
         * 工作簿
         */
        private Workbook wb;

        /**
         * 表单
         */
        private Sheet sheet;

        private void init(FileInfo fileInfo) throws IOException {
            String fileName = fileInfo.getName();
            if(StringUtils.isBlank(fileName)) {
                throw new IllegalArgumentException("导入的文档名称不能为空");
            }

            if(fileName.toLowerCase().endsWith("xls")) {
                this.wb = new HSSFWorkbook(fileInfo.getInput());
            } else if(fileName.toLowerCase().endsWith("xlsx")) {
                this.wb = new XSSFWorkbook(fileInfo.getInput());
            } else {
                throw new IllegalArgumentException("导入的文档不是Excel格式： " + fileName);
            }

            this.headerIndex = fileInfo.getHeaderIndex();
            this.sheetIndex = fileInfo.getSheetIndex();
            this.sheet = this.wb.getSheetAt(this.sheetIndex);
            this.wb.setSheetName(this.sheetIndex, fileInfo.getSheetName());

        }

        private void resolveData(FileInfo fileInfo) throws IOException {
            //数据开始行，为表头标题的下一行
            int dataRow = this.headerIndex + 1;

            //sheet页的最后一行
            int lastRowNum = this.sheet.getLastRowNum() + 1;

            //用list存储数据
            List<Map<String, Object>> datas = new ArrayList<>(lastRowNum - dataRow);

            //计算列数
            int columnSize = fileInfo.getHeads().size();

            for(int i = dataRow; i< lastRowNum; i++) {
                Row row = this.getRow(i);

                //保存没有数值的行
                int blankColumns = 0;

                Map<String, Object> data = new HashMap<>(columnSize);
                List<Head> heads = fileInfo.getHeads();
                for(Head head : heads) {
                    String cellValue = getCellValue(row, head.getIndex());
                    if(StringUtils.isBlank(cellValue)) {
                        blankColumns++;
                    } else {
                        data.put(head.getFieldName(), head.convertType(cellValue));
                    }
                }

                //全是空格，数据不可用
                if(blankColumns == columnSize) {
                    continue;
                }

                datas.add(data);
            }

            fileInfo.setData(datas);
        }

        private Row getRow(int rowNum) {
            return this.sheet.getRow(rowNum);
        }

        private String getCellValue(Cell cell) {
            if(cell != null) {
                switch (cell.getCellType()) {
                    case Cell.CELL_TYPE_NUMERIC:
                        return new BigDecimal(cell.getNumericCellValue()).toString();
                    case Cell.CELL_TYPE_FORMULA:
                        return cell.getCellFormula();
                    case Cell.CELL_TYPE_BOOLEAN:
                        Boolean b = cell.getBooleanCellValue();
                        return b.toString();
                    case Cell.CELL_TYPE_ERROR:
                        Byte by = cell.getErrorCellValue();
                        return by.toString();
                    case Cell.CELL_TYPE_STRING:
                        return cell.getStringCellValue();
                    default:
                }
            }
            return null;
        }

        private String getCellValue(Row row, int column){
            String val = null;
            try{
                Cell cell = row.getCell(column);
                val = getCellValue(cell);
            }catch (Exception e) {
                //ignore
            }
            return val;
        }
    }
}
